"""
行政区划 | 业务层

特殊说明：
    - 行政区划目前只支持到 街道 级别
    - 行政区划编号的长度为：2、4、6、9，分别对应：省、市、区、街道
    - 行政区划目前拉取到的数据未包括：香港、澳门、台湾（后续拿到数据了，会更新），目前只有 31 个省级区划（包括直辖市和自治区）
"""

import utils.enum_utils as enum
from biz.base_biz import (
    GetterBase,
    ValidatorBase,
)
from mapping import RegionMapping
from models import (
    PageQuery,
    POPage,
)
from models.po import (
    RegionAreaPO,
    RegionCityPO,
    RegionProvincePO,
    RegionStreetPO,
)
from models.request import (
    RegionDetailRequest,
    RegionListRequest,
)
from models.vo import (
    RegionDetailVO,
    RegionListPage,
)
from my_typing import *
from service import (
    RegionAreaService,
    RegionCityService,
    RegionProvinceService,
    RegionStreetService,
)
from utils.exception_utils import BusinessError

TypeUnionService = type[RegionProvinceService | RegionCityService | RegionAreaService | RegionStreetService]
UnionPO = RegionProvincePO | RegionCityPO | RegionAreaPO | RegionStreetPO


def get_code_length(code: StrOrNone) -> int:
    """ 获取 code 的长度（None 的时候为 0） """

    if code is None:
        return 0

    return len(code)


CODE_LENGTH_2_LEVEL: dict[int, enum.RegionLevel] = {
    2: enum.RegionLevel.PROVINCE,
    4: enum.RegionLevel.CITY,
    6: enum.RegionLevel.AREA,
    9: enum.RegionLevel.STREET,
}
"""
编号长度 -> 行政区划等级

- 2: 省
- 4: 市
- 6: 区
- 9: 街道
"""

CODE_LENGTH_2_PARENT_CODE_FIELD: dict[int, StrOrNone] = {
    2: None,
    4: "province_code",
    6: "city_code",
    9: "area_code",
}
"""
编号长度 -> 父级编号的字段名

- 2: None
- 4: province_code
- 6: city_code
- 9: area_code
"""

PARENT_CODE_LENGTH_2_SERVICE: dict[int, TypeUnionService] = {
    0: RegionProvinceService,
    2: RegionCityService,
    4: RegionAreaService,
    6: RegionStreetService,
}
"""
父级编号长度 -> Service

- 0: ProvinceService
- 2: CityService
- 4: AreaService
- 6: StreetService
"""

PARENT_CODE_LENGTH_2_QUERY_CODE_FIELD: DictIntStr = {
    2: "province_code",
    4: "city_code",
    6: "area_code",
}
"""
父级编号长度 -> 查询的编号字段名

- 2: province_code
- 4: city_code
- 6: area_code
"""

REGION_LEVEL_2_SERVICE: dict[enum.RegionLevel, TypeUnionService] = {
    enum.RegionLevel.PROVINCE: RegionProvinceService,
    enum.RegionLevel.CITY: RegionCityService,
    enum.RegionLevel.AREA: RegionAreaService,
    enum.RegionLevel.STREET: RegionStreetService,
}
"""
行政区划等级 -> Service

- 省: ProvinceService
- 市: CityService
- 区: AreaService
- 街道: StreetService
"""


def get_region_level_by_code(code: str) -> enum.RegionLevel | None:
    """
    根据编号获取行政区划级别

    Args:
        code: 行政区划编号

    Returns:
        行政区划等级
    """

    return CODE_LENGTH_2_LEVEL.get(len(code))


def get_service_by_region_level(region_level: enum.RegionLevel) -> TypeUnionService:
    """
    根据编行政区划等级获取 Service

    Args:
        region_level: 行政区划等级

    Returns:
        Service
    """

    return REGION_LEVEL_2_SERVICE[region_level]


def get_service_by_parent_code(parent_code: StrOrNone) -> TypeUnionService | None:
    """
    根据 父级编号 获取 Service

    Args:
        parent_code: 父级编号

    Returns:
        Service
    """

    code_length: int = (
        len(parent_code)
        if parent_code
        else 0
    )

    return PARENT_CODE_LENGTH_2_SERVICE.get(code_length)


def get_query_code_field_by_parent_code(parent_code: StrOrNone) -> StrOrNone:
    """
    根据 父级编号 获取 查询的 code 字段名

    Args:
        parent_code: 父级编号

    Returns:
        code 字段名
    """

    if parent_code is None:
        return None

    return PARENT_CODE_LENGTH_2_QUERY_CODE_FIELD.get(len(parent_code))


def get_parent_code_field_by_code(code: StrOrNone) -> StrOrNone:
    """
    根据 code 获取 父级编号的字段名

    Args:
        code: 编号

    Returns:
        父级编号的字段名
    """

    if code is None:
        return None

    return CODE_LENGTH_2_PARENT_CODE_FIELD.get(len(code))


def get_fullpath_code_2_name(code: str) -> DictStrStr:
    """ 获取全路径编号到名称的映射 """

    code_2_name: DictStrStr = {}
    current_code: str = code

    while current_code:
        region_level: enum.RegionLevel = get_region_level_by_code(current_code)
        service: TypeUnionService = get_service_by_region_level(region_level)
        region_po: UnionPO | None = service.get_one_by_code(current_code)

        if region_po is None:
            break

        code_2_name[region_po.code] = region_po.name
        parent_code_field: StrOrNone = get_parent_code_field_by_code(region_po.code)

        if not parent_code_field:
            break

        current_code = getattr(region_po, parent_code_field, None)

    reversed_dict: DictStrStr = {
        k: code_2_name[k]
        for k in reversed(code_2_name)
    }
    """
    反转后的字典

    反转前：
        {
            "330102001": "清波街道",
            "330102": "上城区",
            "3301": "杭州市",
            "33": "浙江省",
        }

    反转后：
        {
            "33": "浙江省",
            "3301": "杭州市",
            "330102": "上城区",
            "330102001": "清波街道",
        }
    """

    return reversed_dict


class RegionValidator(ValidatorBase):
    """ 行政区划 | 校验器 """

    @staticmethod
    def validate_code_valid(code: StrOrNone) -> None:
        """ 校验 code 是否合法 """

        if code is None:
            return None

        region_level: enum.RegionLevel | None = get_region_level_by_code(code)

        if region_level is None:
            raise BusinessError(f"行政区划 编号 <{code}> 不合法")

    @staticmethod
    def validate_exist_by_code(code: str) -> None:
        """ 校验 code 是否存在 """

        region_level: enum.RegionLevel = get_region_level_by_code(code)
        service: TypeUnionService = get_service_by_region_level(region_level)

        if not service.exists({"code": code}):
            raise BusinessError(f"行政区划 编号 <{code}> 不存在")

    @classmethod
    def validate_detail(cls, request: RegionDetailRequest) -> None:
        """
        校验 | 详情

            1. 行政区划编号是否合法
            2. 行政区划编号是否存在
        """

        cls.validate_union(
            {"code": request.code},
            cls.validate_code_valid,
            cls.validate_exist_by_code,
        )

        region_level: enum.RegionLevel | None = get_region_level_by_code(request.code)

        if region_level is None:
            raise BusinessError(f"行政区划 编号 <{request.code}> 不合法")

        service: TypeUnionService = get_service_by_region_level(region_level)

        if not service.exists({"code": request.code}):
            raise BusinessError(f"行政区划 编号 <{request.code}> 不存在")


class RegionGetter(GetterBase):
    """ 行政区划 | 获取器 """

    @classmethod
    def detail(cls, request: RegionDetailRequest) -> RegionDetailVO:
        """ 行政区划 | 详情 """

        RegionValidator.validate_detail(request)
        region_level: enum.RegionLevel = get_region_level_by_code(request.code)
        service: TypeUnionService = get_service_by_region_level(region_level)
        region_po: UnionPO = service.get_one_by_code(request.code)

        return RegionMapping.po_2_detail_vo(region_po)

    @classmethod
    def list(cls, request: RegionListRequest) -> RegionListPage:
        """ 行政区划 | 列表 """

        RegionValidator.validate_code_valid(request.parent_code)
        page_query: PageQuery = cls.get_list_page_query(request)
        service: TypeUnionService = get_service_by_parent_code(request.parent_code)
        region_po_page: POPage[UnionPO] = service.paginated_query(page_query)

        return RegionMapping.po_page_2_vo_page(region_po_page)  # noqa: ignore[attr type]

    @classmethod
    def get_list_query(cls, request: RegionListRequest) -> dict:
        condition = cls.Condition()

        condition.add_regex("name", value=request.name)

        if code_field := get_query_code_field_by_parent_code(request.parent_code):
            condition.add_eq(code_field, value=request.parent_code)

        return condition.get_query()


if __name__ == '__main__':
    from devtools import debug

    debug(get_fullpath_code_2_name("330102001"))
